/* This file is apart of rtodo
 * 
 * Copyright (c) 2008, Ryan Capote
 * All rights reserved
 * Released under the BSD license
 */
#include <iostream>
#include <string>
#include <list>
#include <map>

#include "task.h"
#include "rtodo.h"

const std::string VERSION = "1.0";
const std::string DATE = "10/25/2008";
const std::string AUTHOR = "Ryan Capote (trooper777@gmail.com)";
const std::string COPYRIGHT = "Copyright (c) 2008, Ryan Capote";
const std::string LICENSE = "Code released under the BSD license";
const std::string WEBSITE = "http://code.google.com/p/rtodo";


#if defined(__APPLE__) || defined(__LINUX__)
#include <stdlib.h>
std::string homedir = getenv("HOME");
std::string PATH = homedir + "/";
#else
const std::string PATH = getCwd() + "/";
#endif

const std::string FILENAME = "todo.txt";

enum Actions
{
    VIEW_PROJECT = 0,
    VIEW_CONTEXT,
    VIEW_PRIORITY,
    VIEW_ALL,
    VIEW_NEXT,
    CLEAR_LIST,
    TOGGLE_DONE,
    TOGGLE_NEXT,
    CHANGE_PRIORITY,
    CHANGE_CONTEXT,
    CHANGE_PROJECT,
    CHANGE_TASK,
    ADD_TASK,
    DELETE_TASK
};

std::string combineList(std::list<std::string> list);
void printUsage();
void printHelp();
void printVersion();


int main(int argc, char *argv[])
{   
    //Task task("[ ]+ Call Joe blow (!5 @project #context)");   
    //std::cout << task.serialize() << std::endl;

    //std::map<int, Task*> list = loadTodoMap(getCwd() + "/");
    //viewTasks(list);
    
    //std::list<Task*> list2 = prioritizeList(list, SORT_DESCENDING);
    
    //viewContext("context", list2);
    
    /*
    for(std::list<Task*>::iterator iter = list2.begin(); iter != list2.end(); iter++)
    {
        view((*iter)->getId(), (*iter));
    }*/
    
    // If we don't have any arguments, print the 
    // usage and exit
    if(argc <= 1)
    {
        printUsage();
        return 0;
    }
    
    // We convert the argument to a std::list of std::strings
    // to make our lives so much easier.
    std::list<std::string> argList = convertArguments(argc, argv);    
    std::list<std::string>::iterator argItr;
    
    //std::cout << combineList(argList) << std::endl;

    Actions action;
    SortDir sort = SORT_NONE;
    std::string parameters;
    
    // Go through all of the arguments and handle 
    // the options.
    for(argItr = argList.begin(); argItr != argList.end();)
    {
        //std::cout << *argItr << std::endl;
        if((*argItr) == "-h")
        {
            printHelp();
            return 0;
        }
        else if((*argItr) == "-v")
        {
            printVersion();
            return 0;
        }
        else if((*argItr) == "-pa")
        {
            sort = SORT_ASCENDING;
            argList.erase(argItr++);            
        }
        else if((*argItr) == "-pd")
        {
            sort = SORT_DESCENDING;
            argList.erase(argItr++);
        }
        else if((*argItr) == "clear")
        {
            action = CLEAR_LIST;
            argList.erase(argItr++);
            break;
        }
        else if((*argItr) == "done")
        {
            action = TOGGLE_DONE;
            argList.erase(argItr++);
            break;
        }
        else if((*argItr) == "next")
        {
            action = TOGGLE_NEXT;
            argList.erase(argItr++);
            break;
        }
        // Outputs the whole list of tasks
	else if((*argItr) == "viewtasks" || 
                (*argItr) == "view")
        {
            action = VIEW_ALL;
            argList.erase(argItr++);
            break;
        }
        else if((*argItr) == "viewnext")
        {
            action = VIEW_NEXT;
            argList.erase(argItr++);
            break;
        }
        // Simply print the list of tasks in a project
        else if((*argItr) == "viewproject")
        {
            action = VIEW_PROJECT;
            // Delete this argument since we have already
            // parsed it
            argList.erase(argItr++);
            break;
        }
        // Simply print the list of tasks in a context
        else if((*argItr) == "viewcontext")
        {
            action = VIEW_CONTEXT;
            // Delete this argument since we have already
            // parsed it
            argList.erase(argItr++);
            break;
        }
	else if((*argItr) == "chpriority")
	{
	    action = CHANGE_PRIORITY;
	    argList.erase(argItr++);
	    break;
	}
	else if((*argItr) == "chcontext")
	{
	    action = CHANGE_CONTEXT;
	    argList.erase(argItr++);
	    break;
	}
	else if((*argItr) == "chproject")
	{
	     action = CHANGE_PROJECT;
	     argList.erase(argItr++);
	     break;
	}
	else if((*argItr) == "chtask")
	{
	     action = CHANGE_TASK;
	     argList.erase(argItr++);
	     break;
	}
	else if((*argItr) == "add" ||
		(*argItr) == "a")
	{
	     action = ADD_TASK;
	     argList.erase(argItr++);
	     break;
	}
	else if((*argItr) == "delete" ||
		(*argItr) == "d")
	{
	     action = DELETE_TASK;
	     argList.erase(argItr++);
	     break;
	} 
        else
        {
            std::cout << "Unknown argument: " << (*argItr) << std::endl;
	    argList.erase(argItr++);
        }
    }
    
    if(action == VIEW_PROJECT)
    {
	
        std::string project = argList.front();
        if(project.empty())
        {
            std::cout << "Project not specified." << std::endl;
            return 0;
        }
        else
        {
            std::list<Task*> list = loadTodoList(PATH + FILENAME);
            
            if(sort != SORT_NONE)
                list = prioritizeList(list, sort);
                
            viewProject(project, list);
        }
        
    }
    else if(action == VIEW_CONTEXT)
    {
        std::string context = argList.front();
        if(context.empty())
        {
            std::cout << "Context not specified." << std::endl;
            return 0;
        }
        else
        {
            std::list<Task*> list = loadTodoList(PATH + FILENAME);
            
            if(sort != SORT_NONE)
                list = prioritizeList(list, sort);
            
            viewContext(context, list);
        }
    }
    else if(action == VIEW_ALL)
    {
        std::list<Task*> list = loadTodoList(PATH + FILENAME);
        
        if(sort != SORT_NONE)
            list = prioritizeList(list, sort);
            
        viewTasks(list);
    }
    else if(action == VIEW_NEXT)
    {
        std::list<Task*> list = loadTodoList(PATH + FILENAME);
        
        if(sort != SORT_NONE)
            list = prioritizeList(list, sort);
            
        viewNext(list);
    }
    else if(action == CLEAR_LIST)
    {
        std::list<Task*> list = loadTodoList(PATH + FILENAME);
        clearList(list);
        save(list, PATH + FILENAME);
    }
    else if(action == TOGGLE_DONE)
    {
        std::list<Task*> list = loadTodoList(PATH + FILENAME);
        std::string ids = argList.front();
        int id = atoi(ids.c_str());

	if(id == 0)
	     return 0;

        toggleDone(list, id);
        save(list, PATH + FILENAME);
    }
    else if(action == TOGGLE_NEXT)
    {
        std::list<Task*> list = loadTodoList(PATH + FILENAME);
        std::string ids = argList.front();
        int id = atoi(ids.c_str());
        toggleNext(list, id);
        save(list, PATH + FILENAME);
    }
    else if(action == CHANGE_PRIORITY)
    {
	// chpriority id priority
	// chpriority 2 4
	std::list<Task*> list = loadTodoList(PATH + FILENAME);
	std::string ids = argList.front();
	int id = atoi(ids.c_str());
	argList.pop_front();
	std::string priors = argList.front();
	int priority = atoi(priors.c_str());
	changePriority(list, id, priority);
	save(list, PATH + FILENAME);
    }
    else if(action == CHANGE_CONTEXT)
    {
	// chcategory id category
	// chcategory 3 email
	std::list<Task*> list = loadTodoList(PATH + FILENAME);
	std::string ids = argList.front();
	int id = atoi(ids.c_str());

	if(id == 0)
	     return 0;

	argList.pop_front();
	std::string context = argList.front();
	changeContext(list, id, context);
	save(list, PATH + FILENAME);
    }
    else if(action == CHANGE_PROJECT)
    {
	// chcategory id category
	// chcategory 3 EagleProject
	std::list<Task*> list = loadTodoList(PATH + FILENAME);
	std::string ids = argList.front();
	int id = atoi(ids.c_str());
	
	if(id == 0)
	     return 0;

	argList.pop_front();
	std::string project = argList.front();
	changeProject(list, id, project);
	save(list, PATH + FILENAME);

    }
    else if(action == CHANGE_TASK)
    {
         std::list<Task*> list = loadTodoList(PATH + FILENAME);
	 std::string ids = argList.front();
	 int id = atoi(ids.c_str());
	 
	 if(id == 0)
	      return 0;

	 argList.pop_front();
	 std::string task = combineList(argList);
	 changeTask(list, id, task);
	 save(list, PATH + FILENAME);

    }
    else if(action == ADD_TASK)
    {
	// Get the priority
    	std::string priors = argList.front();
	int priority = atoi(priors.c_str());

	if(priority == 0)
	     priority = 1;

	argList.pop_front();

	// check to see if we have a context and/or project
	// @ = project, # = context
	std::string next = argList.front();
	std::string project = "none";
	std::string context = "none";
	//std::cout << next.at(0);

	if(next.at(0) == '@')
	{
	     project = next.erase(0, 1);
	     argList.pop_front();
	     next = argList.front();
	}
	if(next.at(0) == '#')
	{
	     context = next.erase(0, 1);
	     argList.pop_front();
	}

	std::string task = combineList(argList);

	std::cout << project << " - " << context << " - " << task << std::endl;

	addTask(PATH + FILENAME, task, priority, context, project);

    }
    else if(action == DELETE_TASK)
    {
         std::list<Task*> list = loadTodoList(PATH + FILENAME);
	 std::string tasks = argList.front();
	 int task = atoi(tasks.c_str());

	 if(task == 0)
	      return 0;

	 deleteTask(list, task);
    }

    return 0;
}

/*!
 * Comebines a list of strings into a single string
 */
std::string combineList(std::list<std::string> list)
{
    std::string result;
    std::stringstream resultStream;
    
    std::list<std::string>::iterator iter;

    for(iter = list.begin(); iter != list.end(); )
    {
    	resultStream << (*iter) << " ";
    	list.erase(iter++);
    }

    result = resultStream.str();
    return result;

}


/*!
 * Outputs the usage of the command to the standard output.
 */
void printUsage()
{
    std::cout << "Usage: rtodo [options] [ACTION] [PARAM...]" << std::endl;
    std::cout << "Try 'rtodo -h' for more information." << std::endl;
    std::cout << "The task list will be stored in the directory the command is executed." << std::endl;
}

/*!
 * Outputs the help documentation of the command to the standard output.
 */
void printHelp()
{
    std::cout << "Usage: rtodo [options] [ACTION] [PARAM...]" << std::endl
              << "The task list will be stored in the directory the command is executed." << std::endl
              << std::endl
              << "Actions:" << std::endl
              << "   add [PRIORITY] @project '#context' [TASK] \"add 5 @EagleProject '#phone' Call joe\"" << std::endl
              << "   a   [PRIORITY] @project '#context' [TASK] \"a 5 @WebSite '#computer' Implement the feature\"" << std::endl
              << "      Adds a task to your todo list." << std::endl
              << "      Project and context are optional." << std::endl
              << "      Priority between 1 and 5." << std::endl
	      << "      Due to technical difficulties, the context needs to have quotes." << std::endl
              << std::endl
	      << "   delete [ID] \"delete 5\"" << std::endl
	      << "   d [ID] \"d 5\"" << std::endl
	      << "      Deletes the specified task" << std::endl
	      << std::endl
              << "   clear \"clear\"" << std::endl
              << "       This removes all finished tasks frp, the list" << std::endl
              << std::endl
              << "   done [ID] \"done 4\"" << std::endl
              << "        Toggles whether a task is done" << std::endl
              << std::endl
              << "   next [ID] \"next 3\"" << std::endl
              << "        Toggle whether a task is a next action" << std::endl
              << std::endl
              << "   viewproject [PROJECT] \"viewproject project\"" << std::endl
              << "      Prints all tasks in a specific project." << std::endl
              << std::endl
              << "   viewcontext [CONTEXT] \"viewcontext context\"" << std::endl
              << "       Prints all tasks in a specific context" << std::endl
              << std::endl
              << "   view \"view\"" << std::endl
              << "   viewtasks \"viewtasks\"" << std::endl
              << "       Prints all tasks." << std::endl
              << std::endl
              << "   viewnext \"viewnext\"" << std::endl
              << "        Prints all next action tasks." << std::endl
	      << std::endl
	      << "   chpriority [ID] [PRIORITY] \"chpriorty 5 4\"" << std::endl
	      << "        Changes the priority of a task" << std::endl
              << std::endl
	      << "   chcontext [ID] [CONTEXT] \"chcontext 5 email\"" << std::endl
	      << "        Changes the context of a task" << std::endl
	      << std::endl
	      << "   chproject [ID] [PROJECT] \"chproject 5 EagleProject\"" << std::endl
	      << "        Changes the project of a task" << std::endl
	      << std::endl
	      << "   chtask [ID] [TASK] \"chtask 5 Call Jim\"" << std::endl
	      << "         Changes the task description" << std::endl
	      << std::endl
              << std::endl 
              << "Arguments:" << std::endl
              << "   -pa Sort list by priority ascending" << std::endl
              << "   -pd Sort list by priority descending" << std::endl
              << "   -v Outputs the version information" << std::endl;
              
}

/*!
 * Outputs the version information to the standard output.
 */
void printVersion()
{
    std::cout << "rtodo v"
              << VERSION << " " << DATE << std::endl
              << AUTHOR << std::endl
              << COPYRIGHT << std::endl
              << LICENSE << std::endl
	      << WEBSITE << std::endl;
}


